﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Ciloci.Flee;
using Ciloci.Flee.CalcEngine;
using NCalc;
using OPC.Common;
using OPC.Data;
using SimpleSim.SimEngine;


namespace SimpleSim.ConsoleApplication
{
    class Program
    {
        private static int[] opcServerHandles = new int[2];
        private static OpcGroup opcGroup;


        static void Main(string[] args)
        {
            //bool run = true;

            //while(run)
            //{
            //    CalculationEngine engine = new CalculationEngine();
            //    ExpressionContext context = new ExpressionContext();
            //    VariableCollection variables = context.Variables;

            //    context.Imports.AddType(typeof(AnalogTag));

            //    variables.Add("TAG0", new AnalogTag());

            //    Console.Write("Iterations?: ");
            //    int iterations = Convert.ToInt32(Console.ReadLine());

            //    Stopwatch stopwatch = new Stopwatch();

            //    stopwatch.Start();
            //    for (int i = 0; i < iterations; i++)
            //    {
            //        variables.Add("TAG" + (i + 1), new AnalogTag());
            //        engine.Add("e" + (i + 1), string.Format("TAG{0}.SetRawValue(TAG{1}.RawValue)", i + 1, i), context);
            //    }
            //    stopwatch.Stop();
            //    Console.WriteLine("Load Engine: {0} ms", stopwatch.Elapsed.TotalMilliseconds);

            //    stopwatch.Reset();
            //    stopwatch.Start();
            //    ((AnalogTag)variables["TAG0"]).RawValue = 66;
            //    stopwatch.Stop();
            //    Console.WriteLine("Set Value: {0} ms", stopwatch.Elapsed.TotalMilliseconds);


            //    stopwatch.Reset();
            //    stopwatch.Start();
            //    engine.Recalculate();
            //    stopwatch.Stop();

            //    Console.WriteLine("First Recalculate: {0} ms", stopwatch.Elapsed.TotalMilliseconds);
                
            //    stopwatch.Reset();
            //    stopwatch.Start();
            //    engine.Recalculate();
            //    stopwatch.Stop();
            //    Console.WriteLine("Second Recalculate: {0} ms", stopwatch.Elapsed.TotalMilliseconds);

            //    Console.WriteLine("q to Quit, Enter to Continue...");
            //    if (Console.ReadLine() == "q")
            //        run = false;
            //}

            //Expression expression = new Expression("PIT2705+3");
            //expression.EvaluateParameter += EvaluateParameter;



            //Console.WriteLine(expression.Evaluate());
            //Console.WriteLine("Hit Enter to Continue...");
            //Console.ReadLine();

            //return;

            OpcServer opcServer = new OpcServer();
            opcServer.Connect("HWHsc.OPCServer");
            Thread.Sleep(500);

            // add our only working group
            opcGroup = opcServer.AddGroup("OPCCSharp-Group", false, 1000);

            // add two items and save server handles
            OPCItemDef[] opcItemDefs = new OPCItemDef[2];
            opcItemDefs[0] = new OPCItemDef("/ASSETS/P01_DOILG/DEOILED_TK/DEOILED_T1330/P01_FI_1335A.FIT_1335A.PV", true, 1234, VarEnum.VT_EMPTY);
            opcItemDefs[1] = new OPCItemDef("/ASSETS/P01_DOILG/DEOILED_TK/DEOILED_T1330/P01_FI_1335B.FIT_1335B.PV", true, 5678, VarEnum.VT_EMPTY);

            OPCItemResult[] opcItemResults;
            opcGroup.AddItems(opcItemDefs, out opcItemResults);
            if (opcItemResults == null)
                return;
            if (HRESULTS.Failed(opcItemResults[0].Error) || HRESULTS.Failed(opcItemResults[1].Error))
            { Console.WriteLine("OPC Tester: AddItems - some failed"); opcGroup.Remove(true); opcServer.Disconnect(); return; };

            opcServerHandles[0] = opcItemResults[0].HandleServer;
            opcServerHandles[1] = opcItemResults[1].HandleServer;

            // asynch read our two items
            opcGroup.SetEnable(true);
            opcGroup.Active = true;
            opcGroup.DataChanged += OpcGroupDataChanged;
            opcGroup.ReadCompleted += OpcGroupReadCompleted;
            int cancelID;
            int[] aE;
            opcGroup.Read(opcServerHandles, 55667788, out cancelID, out aE);

            // some delay for asynch read-complete callback (simplification)
            Thread.Sleep(500);

            // asynch write
            object[] itemValues = new object[2];
            itemValues[0] = 1111111;
            itemValues[1] = 2322.2222;
            opcGroup.WriteCompleted += OpcGroupWriteCompleted;
            opcGroup.Write(opcServerHandles, itemValues, 99887766, out cancelID, out aE);

            //// some delay for asynch write-complete callback (simplification)
            Thread.Sleep(500);


            // disconnect and close
            Console.WriteLine("************************************** hit <return> to close...");
            Console.ReadLine();
            opcGroup.DataChanged -= OpcGroupDataChanged;
            //opcGroup.ReadCompleted -= OpcGroupReadCompleted;
            opcGroup.WriteCompleted -= OpcGroupWriteCompleted;
            opcGroup.RemoveItems(opcServerHandles, out aE);
            opcGroup.Remove(false);
            opcServer.Disconnect();
        }


        private static void EvaluateParameter(string name, ParameterArgs args)
        {
            if(name == "PIT2705")
            {
                args.Result = 0;
            }
            else
            {
                throw new Exception(string.Format("The TAG {0} was not found in the database...", name));
            }
        }

        public static void OpcGroupDataChanged(object sender, DataChangeEventArgs e)
        {
            Console.WriteLine("DataChange event: gh={0} id={1} me={2} mq={3}", e.groupHandleClient, e.transactionID, e.masterError, e.masterQuality);
            foreach (OPCItemState s in e.sts)
            {
                if (HRESULTS.Succeeded(s.Error))
                    Console.WriteLine(" ih={0} v={1} q={2} t={3}", s.HandleClient, s.DataValue, s.Quality, s.TimeStamp);
                else
                    Console.WriteLine(" ih={0}    ERROR=0x{1:x} !", s.HandleClient, s.Error);
            }
            foreach (var opcItemState in e.sts)
            {
                if(opcItemState.HandleClient == 1234)
                {
                    int cancelID;
                    int[] aE;
                    opcGroup.Write(new[] { opcServerHandles[1] }, new[] { opcItemState.DataValue }, 99887766, out cancelID, out aE);
                }
            }
        }

        public static void OpcGroupReadCompleted(object sender, ReadCompleteEventArgs e)
        {
            Console.WriteLine("ReadComplete event: gh={0} id={1} me={2} mq={3}", e.groupHandleClient, e.transactionID, e.masterError, e.masterQuality);
            foreach (OPCItemState s in e.sts)
            {
                if (HRESULTS.Succeeded(s.Error))
                    Console.WriteLine(" ih={0} v={1} q={2} t={3}", s.HandleClient, s.DataValue, s.Quality, s.TimeStamp);
                else
                    Console.WriteLine(" ih={0}    ERROR=0x{1:x} !", s.HandleClient, s.Error);
            }
        }

        public static void OpcGroupWriteCompleted(object sender, WriteCompleteEventArgs e)
        {
            Console.WriteLine("WriteComplete event: gh={0} id={1} me={2}", e.groupHandleClient, e.transactionID, e.masterError);
            foreach (OPCWriteResult r in e.res)
            {
                if (HRESULTS.Succeeded(r.Error))
                    Console.WriteLine(" ih={0} e={1}", r.HandleClient, r.Error);
                else
                    Console.WriteLine(" ih={0}    ERROR=0x{1:x} !", r.HandleClient, r.Error);
            }
        }
    }
}
